<?php

class App
{
    /** @var array */
    public array $get;
    /** @var array */
    public array $post;
    /** @var array */
    public array $server;
    /** @var string */
    public string $method;
    /** @var string */
    public string $uri;
    /** @var string */
    public string $body;
    /** @var array */
    public array $cookies;
    /** @var array */
    public array $headers;

    /** @var string */
    protected static string $logFile = __DIR__ . '/../public/storage/logs/app.log';

    /**
     * App constructor.
     * Initializes request superglobals and headers.
     */
    public function __construct()
    {
        $this->get     = $_GET ?? [];
        $this->post    = $_POST ?? [];
        $this->server  = $_SERVER ?? [];
        $this->method  = $this->server['REQUEST_METHOD'] ?? 'GET';
        $this->uri     = parse_url($this->server['REQUEST_URI'] ?? '/', PHP_URL_PATH);
        $this->body    = file_get_contents('php://input') ?: '';
        $this->cookies = $_COOKIE ?? [];
        $this->headers = function_exists('getallheaders') ? getallheaders() : [];
    }

    // -------------------------------------------------------------------------
    // Request Helpers
    // -------------------------------------------------------------------------

    /**
     * Get input value from POST or GET with fallback.
     *
     * @param string $key
     * @param mixed $default
     * @return mixed
     */
    public function input(string $key, $default = null)
    {
        return $this->post[$key] ?? $this->get[$key] ?? $default;
    }

    /**
     * Check if the request method matches.
     *
     * @param string $method
     * @return bool
     */
    public function is(string $method): bool
    {
        return strtoupper($this->method) === strtoupper($method);
    }

    // -------------------------------------------------------------------------
    // Response Helpers
    // -------------------------------------------------------------------------

    /**
     * Set a response header.
     *
     * @param string $key
     * @param string $value
     * @return self
     */
    public function header(string $key, string $value): self
    {
        header("$key: $value");
        return $this;
    }

    /**
     * Set HTTP status code.
     *
     * @param int $code
     * @return self
     */
    public function status(int $code): self
    {
        http_response_code($code);
        return $this;
    }

    /**
     * Return JSON response.
     *
     * @param mixed $data
     * @param int $status
     * @param array $headers
     * @return self
     */
    public function json($data, int $status = 200, array $headers = []): self
    {
        $this->status($status)->header('Content-Type', 'application/json');
        foreach ($headers as $key => $value) {
            $this->header($key, $value);
        }
        echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
        return $this;
    }

    /**
     * Render a view.
     *
     * @param string $page
     * @param array $data
     * @return self
     * @throws Exception
     */
    public function view(string $page, array $data = []): self
    {
        self::renderView($page, $data);
        return $this;
    }

    /**
     * Return plain text response.
     *
     * @param string $content
     * @return self
     */
    public function text(string $content): self
    {
        $this->header('Content-Type', 'text/plain');
        echo $content;
        return $this;
    }

    /**
     * Redirect to a URL.
     *
     * @param string $url
     * @param int $code
     */
    public function redirect(string $url, int $code = 302): void
    {
        $this->status($code)->header('Location', $url);
        exit;
    }

    // -------------------------------------------------------------------------
    // Core App Logic
    // -------------------------------------------------------------------------

    /**
     * App kernel. Load routes and dispatch the request.
     */
    public function run(): void
    {
        $routes = require __DIR__ . '/../config/routes.php';
        $router = new Router($routes);
        $router->dispatch($this->uri, $this, $this);
    }

    // -------------------------------------------------------------------------
    // View Renderer
    // -------------------------------------------------------------------------

    /**
     * Simple view renderer.
     *
     * @param string $page
     * @param array $data
     * @throws Exception
     */
    protected static function renderView(string $page, array $data = []): void
    {
        $viewFile = __DIR__ . "/../views/{$page}.php";
        if (!file_exists($viewFile)) {
            throw new Exception("View file not found: {$viewFile}");
        }
        extract($data);
        include $viewFile;
    }

    // -------------------------------------------------------------------------
    // Logging
    // -------------------------------------------------------------------------

    /**
     * Log an info level message.
     *
     * @param string $message
     */
    public static function info(string $message): void
    {
        self::writeLog('INFO', $message);
    }

    /**
     * Log an error level message.
     *
     * @param string $message
     */
    public static function error(string $message): void
    {
        self::writeLog('ERROR', $message);
    }

    /**
     * Write to log file.
     *
     * @param string $level
     * @param string $message
     */
    protected static function writeLog(string $level, string $message): void
    {
        $logDir = dirname(self::$logFile);
        if (!is_dir($logDir)) {
            mkdir($logDir, 0777, true);
        }

        $date = date('Y-m-d H:i:s');
        $formatted = "[$date][$level] $message" . PHP_EOL;

        if (!file_exists(self::$logFile)) {
            touch(self::$logFile);
            chmod(self::$logFile, 0666);
        }

        file_put_contents(self::$logFile, $formatted, FILE_APPEND);
    }
}
